package wiki.hitime.stl.daq.service.task;

import com.alibaba.fastjson.JSON;
import wiki.hitime.stl.daq.bean.base.SyUser;
import wiki.hitime.stl.daq.bean.db.DaqExecuteRule;
import wiki.hitime.stl.daq.bean.dto.req.ExecuteTaskExecuteReqDTO;
import wiki.hitime.stl.daq.manager.DaqExecuteRecordManager;
import wiki.hitime.stl.daq.manager.DaqExecuteRuleManager;
import wiki.hitime.stl.daq.util.CronUtils;
import wiki.hitime.stl.daq.util.UserContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 执行任务类
 *
 * @author zhangdaoping
 * @create 2019-07-10 14:14
 */
@Service
@Slf4j
public class DataExecuteService {

    private DaqExecuteRuleManager daqExecuteRuleManager;
    private DaqExecuteRecordManager daqExecuteRecordManager;
    private DataAcquisitionService dataAcquisitionService;

    public DataExecuteService(DaqExecuteRuleManager daqExecuteRuleManager,
                              DaqExecuteRecordManager daqExecuteRecordManager,
                              DataAcquisitionService dataAcquisitionService) {
        this.daqExecuteRuleManager = daqExecuteRuleManager;
        this.daqExecuteRecordManager = daqExecuteRecordManager;
        this.dataAcquisitionService = dataAcquisitionService;
    }

    /**
     * 执行任务
     */
    @Scheduled(cron = "0 1/1 * * * ?")
    public void executeTask() {
        // 获取下一次执行时间<=当前时间且状态为1-已启用
        List<DaqExecuteRule> pendingTaskList = daqExecuteRuleManager.loadPendingTask();
        SyUser syUser = UserContextUtil.getUser();
        int successCount = pendingTaskList.parallelStream().mapToInt(t -> executeTask(t, syUser)).sum();
        log.info("本次待执行任务数：{}，成功执行数：{}，失败执行数:{}", pendingTaskList.size(), successCount, pendingTaskList.size() - successCount);
    }

    public void executeTask(ExecuteTaskExecuteReqDTO reqDTO) {
        DaqExecuteRule daqExecuteRule = daqExecuteRuleManager.get(reqDTO.getExecuteRuleId());
        SyUser syUser = UserContextUtil.getUser();
        this.executeTask(daqExecuteRule, syUser);
    }

    private int executeTask(DaqExecuteRule daqExecuteRule, SyUser syUser) {
        // 锁定规则
        if (daqExecuteRuleManager.lockTask(daqExecuteRule.getId())) {
            // 保存执行记录
            Long executeRecordId = daqExecuteRecordManager.addNotProcessRecord(daqExecuteRule);
            try {
                UserContextUtil.setUser(syUser);
                DateTime nowDate = DateTime.now();
                dataAcquisitionService.acquisitionData(daqExecuteRule.getId(), executeRecordId);
                // 根据执行时间表达式计算下一次执行时间
                long nextExecuteTime = CronUtils.parserNextFiredTime(daqExecuteRule.getCronExpression(), nowDate.toDate());
                // 修改上一次执行时间和下一次执行时间
                daqExecuteRuleManager.updateNextExecuteTime(daqExecuteRule.getId(), nowDate.getMillis(), nextExecuteTime);
                // 解锁
                daqExecuteRuleManager.unlockTask(daqExecuteRule.getId());
                // 修改记录为成功
                daqExecuteRecordManager.updateProcessSucceed(executeRecordId);
                return 1;
            } catch (Exception e) {
                log.error("执行规则出现未知异常，executeRule={}", JSON.toJSONString(daqExecuteRule), e);
                // 修改记录为失败
                daqExecuteRecordManager.updateProcessFailed(executeRecordId, e.getMessage());
                return 0;
            }
        }
        return 0;
    }

}
